package com.tutu.borrow.controller;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.tutu.borrow.entity.Borrow;
import com.tutu.feign.feignclient.BookClient;
import com.tutu.feign.feignclient.UserClient;
import com.tutu.borrow.service.BorrowService;
import com.tutu.commons.entity.Book;
import com.tutu.commons.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

/**
 * @Program: SpringCloud
 * @Description: BorrowController
 * @Author: JK.TuTu
 * @ @Version: 1.0
 * @Create: 2022-12-01 14:39
 **/
@Slf4j
@RestController
@RequestMapping("/borrow")
public class BorrowController {
    @Resource
    private BorrowService borrowService;

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private DiscoveryClient discoveryClient; //服务注册与发现客户端对象

    @Resource
    private LoadBalancerClient loadBalancerClient; //负载均衡客户端对象

    @Resource
    private UserClient userClient;  //自定义的调用user-server的openfeign的客户端

    @Resource
    private BookClient bookClient;  //自定义的调用book-server的openfeign的客户端
    /**
     * 通过id查询出借阅信息
     * @param id
     * @return
     */

    @HystrixCommand(fallbackMethod = "getBorrowError")  //使用@HystrixCommand来指定该方法的备选方法
    @GetMapping("/getBorrowInfo/{id}")
    public Borrow getBorrow(@PathVariable("id") int id,
                            @RequestHeader(value = "Single",required = false) String single,
                            @RequestHeader(value = "All",required = false) String all){
        //通过id查询图书的借阅信息
        Borrow borrowInfo = borrowService.getBorrowInfo(id);

        //通过用户id查询用户
        //User user = restTemplate.getForObject("http://user-server/user/"+borrowInfo.getUid(), User.class);
        User user = userClient.findUserById(borrowInfo.getUid());


        //1.采用RestTemplate发送请求  通过图书id查询出图书信息
        //Book book = restTemplate.getForObject("http://localhost:8070/book/" + borrowInfo.getBid(), Book.class);

        //2.使用ribbon组件+RestTemplate实现负载均衡 若使用的服务注册中心为eureka,无需单独引入依赖,已经默认集成了ribbon组件 ribbon组件默认使用轮询策略
        /*List<ServiceInstance> bookServer = discoveryClient.getInstances("book_server");
        for (ServiceInstance serviceInstance : bookServer) {
            log.info("服务主机:{}",serviceInstance.getHost());
            log.info("服务端口:{}",serviceInstance.getPort());
            log.info("服务地址:{}",serviceInstance.getUri());
            log.info("------------------------------------------------");
        }
        String url=bookServer.get(0).getUri()+ "/book/"+borrowInfo.getBid();
        Book book = restTemplate.getForObject(url, Book.class);*/


        //3.使用LoadBalancerClient根据负载均衡策略(默认是轮询策略)选取一个服务
        /*ServiceInstance bookServer = loadBalancerClient.choose("book_server");
        log.info("服务主机:[{}]",bookServer.getHost());
        log.info("服务端口:[{}]",bookServer.getPort());
        log.info("服务地址:[{}]",bookServer.getUri());
        log.info("-----------------------------------------------------");
        String url=bookServer.getUri()+ "/book/"+borrowInfo.getBid();
        Book book = restTemplate.getForObject(url, Book.class);*/


        //4.使用@LoadBalanced注解，使得RestTemPlate具有负载均衡特性  此时ip地址必须换成服务名称代替  且服务名称中不能含有下划线
        //Book book = restTemplate.getForObject("http://book-server/book/" + borrowInfo.getBid(), Book.class);

        //5.利用openfeign客户端进行调用
        Book book = bookClient.findBookById(borrowInfo.getBid());
        borrowInfo.setUser(user);
        borrowInfo.setBook(book);

        //打印请求头的内容
        log.info("Single:{}",single);
        log.info("all:{}",all);

        log.info("服务正常,调用其他服务......");
        return borrowInfo;
    }


    /**
     * 备选方法  方法名需要与fallbackMethod的值保持一致且参数和返回值都需要上面的方法保持一致
     * @param id
     * @return
     */
    public Borrow getBorrowError(int id,String single,String all){
        log.info("服务降级,进入备选方法......");
        return new Borrow();
    }
}
